﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SchemesServer.WCFServer
{
    public class SchemesServer : ISchemesServer
    {
        public static event Action<string, bool> Event_OnMessage;

        /// <summary>
        /// 验证密码常量 
        /// </summary>
        private const string CONST_PASSWORD = "YouDoGuess";

        /// <summary>
        /// 服务器授权客户端许可文件对象
        /// </summary>
        private static Comm.Security.ServerLicense ClientsLicense = null;
        /// <summary>
        /// 许可文件对象
        /// </summary>
        private static Comm.Security.ServiceLicense license = null;
        /// <summary>
        /// 文件夹锁
        /// </summary>
        private static object LockDirectoryObject = new object();

        private static object initObj = new object();
        private static bool hasInited = false;

        public SchemesServer()
        {
            if (hasInited == false)
            {
                lock (initObj)
                {
                    if (hasInited == false)
                    {
                        if (license == null)
                        {
                            Comm.Security.ServiceLicense.LicenseDir = System.Environment.CurrentDirectory;
                            license = Comm.Security.ServiceLicense.Load();
                            if (license == null)
                            {
                                OnEventMessage("无法加载服务器许可证文件", true);
                            }
                        }
                        if (ClientsLicense == null)
                        {
                            ClientsLicense = Comm.Security.ServerLicense.LoadLicense(System.Environment.CurrentDirectory);
                            if (license == null)
                            {
                                OnEventMessage("无法加载客户端许可证定义文件", true);
                            }
                        }
                        hasInited = true;
                    }
                }
            }
        }


        /// <summary>
        /// 获取方案获方案目录绝对路径
        /// </summary>
        /// <param name="schemeName">方案名称，可为空</param>
        /// <returns></returns>
        private string GetSchemeFullPath(string schemeName = "")
        {
            string serverPath = string.Format(@"{0}\{1}", System.Environment.CurrentDirectory, "Schemes");

            lock (LockDirectoryObject)
            {
                if (!System.IO.Directory.Exists(serverPath)) System.IO.Directory.CreateDirectory(serverPath);
            }

            if (schemeName.Trim() == "") return serverPath;

            schemeName = schemeName.Replace("\\", "").Replace("/", "");

            return string.Format(@"{0}\{1}{2}", serverPath, schemeName, Comm.Util.SchemeUtils.SchemeExtensionName);
        }

        /// <summary>
        /// 获取方案列表
        /// </summary>
        /// <returns></returns>
        public string[] GetSchemes()
        {
            try
            {
                OnEventMessage(string.Format("【{0:yy-MM-dd HH:mm:ss}】 客户端正在获取方案列表....", DateTime.Now), false);

                string schemeDir = GetSchemeFullPath();

                string[] schemeFiles = System.IO.Directory.GetFiles(schemeDir, "*" + Comm.Util.SchemeUtils.SchemeExtensionName);

                string[] schemeNames = new string[schemeFiles.Length];

                for (int i = 0; i < schemeFiles.Length; i++)
                {
                    schemeNames[i] = (new System.IO.FileInfo(schemeFiles[i])).Name.Replace(Comm.Util.SchemeUtils.SchemeExtensionName, "");
                }

                return schemeNames;
            }
            catch (Exception e)
            {
                OnEventMessage(string.Format("【{0:yy-MM-dd HH:mm:ss}】 客户端获取方案列表失败：{1}....", DateTime.Now, e.Message), true);
                return new string[0];
            }
        }

        /// <summary>
        /// 下载方案
        /// </summary>
        /// <param name="file">方案数据文件对象</param>
        /// <param name="password">验证密码</param>
        /// <param name="hdSerialNumbers">验证磁盘序列号</param>
        /// <returns></returns>
        public DataInfo GetSchemeContent(DataInfo file, string password, string hdSerialNumbers)
        {
            if (file == null)
            {
                return null;
            }
            if (license == null)
            {
                OnEventMessage("下载方案文件出错，服务器没有许可证文件", true);
                return null;
            }

            //相关参数检查
            if (file.Offset == 0)
            {
                if (!password.Equals(CONST_PASSWORD))
                {
                    OnEventMessage(string.Format("客户端：{0} 无效的密码访问被终止....", hdSerialNumbers), true);
                    return null;
                }
                if (!license.IsAuthorized(hdSerialNumbers))
                {
                    OnEventMessage(string.Format("客户端：{0} 未授权的访问被终止....", hdSerialNumbers), true);
                    return null;
                }
            }

            return GetSchemeContentImpl(file, password);
        }

        public DataInfo GetSchemeContentImpl(DataInfo file, string password)
        {
            if (!password.Equals(CONST_PASSWORD))
            {
                OnEventMessage(string.Format("客户端：{0} 无效的密码访问被终止....", "SchemeManger"), true);
                return null;
            }
            string schemePath = GetSchemeFullPath(file.Name);
            if (!System.IO.File.Exists(schemePath)) return null;
            using (System.IO.FileStream fs = new System.IO.FileStream(schemePath, System.IO.FileMode.Open))
            {
                if (fs.Length - file.Offset <= file.BuffLen)
                {
                    file.Data = new byte[fs.Length - file.Offset];
                    OnEventMessage(string.Format("客户端:{0} 下载方案：{1} 完成...", "SchemeManager", file.Name), false);
                }
                else
                {
                    file.Data = new byte[file.BuffLen];
                }
                fs.Position = file.Offset;
                fs.Read(file.Data, 0, file.Data.Length);
                file.Length = fs.Length;
                fs.Close();
            }

            return file;
        }

        private static void OnEventMessage(string message, bool isError)
        {
            if (Event_OnMessage != null)
            {
                Event_OnMessage(message, isError);
            }
        }

        /// <summary>
        /// 上传方案
        /// </summary>
        /// <param name="file">方案数据文件对象</param>
        /// <param name="password">验证密码</param>
        /// <returns></returns>
        public DataInfo UpDataScheme(DataInfo file, string password)
        {
            if (file == null) return null;

            if (file.Data == null || file.Data.Length == 0) return null;

            if (file.Offset == 0)
            {
                if (!password.Equals(CONST_PASSWORD))
                {
                    OnEventMessage("客户端无效的密码访问被终止....", true);
                    return null;
                }
                string schemePath = GetSchemeFullPath(file.Name);
                if (System.IO.File.Exists(schemePath)) System.IO.File.Delete(schemePath);

                file.Name = schemePath;
            }
            else
            {
                if (!System.IO.File.Exists(file.Name)) return null;
            }

            using (System.IO.FileStream fs = new System.IO.FileStream(file.Name, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
            {
                using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs))
                {
                    bw.Seek((int)file.Offset, System.IO.SeekOrigin.Begin);

                    bw.Write(file.Data);

                    file.Offset = fs.Length;

                    file.Data = null;
                    bw.Close();
                }
                fs.Close();
            }

            return file;
        }

        /// <summary>
        /// 删除方案
        /// </summary>
        /// <param name="schemeName">方案名称</param>
        /// <param name="password">验证密码</param>
        /// <returns></returns>
        public string DeleteScheme(string schemeName, string password)
        {
            if (!password.Equals(CONST_PASSWORD)) return "验证失败，无法完成操作...";

            string filepath = GetSchemeFullPath(schemeName);

            lock (LockDirectoryObject)
            {
                if (System.IO.File.Exists(filepath))
                {
                    System.IO.File.Delete(filepath);
                    OnEventMessage(string.Format("客户端删除了方案：{1} 完成...", schemeName), false);
                }
                return "";
            }
        }

        /// <summary>
        /// 获取客户端授权文件
        /// </summary>
        /// <param name="Sn">客户端磁盘序列号（多磁盘，任意选一个）</param>
        /// <returns></returns>
        public byte[] GetClientLicense(string Sn)
        {
            if (Sn == "")
            {
                OnEventMessage(string.Format("获取许可文件出错，为空的客户端序列号..."), false);
                return new byte[0];
            }
            if (license == null || ClientsLicense == null)
            {
                OnEventMessage("没有加载服务器许可文件,无法对客户端进行授权:" + Sn, true);
                return new byte[0];
            }

            if (!license.IsAuthorized(Sn))
            {
                OnEventMessage(string.Format("客户端：{0} 未授权的访问被终止....", Sn), true);
                return null;
            }
            OnEventMessage(string.Format("客户端:{0}正在获取许可证...", Sn), false);
            lock (ClientsLicense)
            {
                byte[] data = ClientsLicense.CreateLicenseFile(Sn);
                if (data == null || data.Length < 1)
                {
                    OnEventMessage("创建客户端许可证文件失败", true);
                }
                else
                {
                    OnEventMessage("创建客户端许可证文件成功", false);
                }
                return data;
            }
        }
    }
}
